package com.mdxx.xczd.utils;

import android.os.Handler;
import android.os.Looper;
import com.google.gson.Gson;
import com.google.gson.internal.$Gson$Types;
import com.orhanobut.logger.Logger;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;

public class OkHttpManager {

	private static OkHttpManager mInstance;
	private OkHttpClient mOkHttpClient;
	private Handler mDelivery;
	private Gson mGson;
	private static final String TAG = "OkHttpClientManager";

	private OkHttpManager(){
		mOkHttpClient = new OkHttpClient();

		mDelivery = new Handler(Looper.getMainLooper());
		mGson = new Gson();
	}

	public static OkHttpManager getInstance(){
		if (mInstance == null){
			synchronized (OkHttpManager.class){
				if (mInstance == null){
					mInstance = new OkHttpManager();
				}
			}
		}
		return mInstance;
	}	


	public  void setprogressListener(){

	}

	public static Response getAsyn(String url) throws IOException{		
		return getInstance().get_Asyn(url);
	}

	public static String getString(String url) throws IOException{
		return getInstance().get_String(url);
	}

	public static void getAsyn(String url, ResultCallback callback) throws IOException{
		getInstance().get_Asyn(url,callback);
	}

	public static Response postAsyn(String url, HeaderParam[] headerParams,Param[] params) throws IOException{
		return getInstance().post_Asyn(url, headerParams, params);
	}

	public static void postAsyn(String url, HeaderParam[] headerParams, Param[] params, ResultCallback callback) throws IOException{
		getInstance().post_Asyn(url, callback, headerParams, params);
	}

	public static void downloadFileAsyn(String url, String destDir, final ProgressListener progressListener,ResultCallback callback) {
		getInstance().downloadAsyn(url, destDir, progressListener, callback);
	}

	/**
	 * 同步get
	 * @param url
	 * @return
	 * @throws IOException
	 */
	private Response get_Asyn(String url) throws IOException{
		Request request = new Request.Builder().url(url).build();
		Response response = mOkHttpClient.newCall(request).execute();
		return response;
	}

	/**
	 * 同步get
	 * @param url
	 * @return
	 * @throws IOException
	 */
	private String get_String(String url) throws IOException{
		Response response = get_Asyn(url);		
		return response.body().string();
	}

	/**
	 * get异步
	 * @param url
	 * @param
	 * @throws IOException
	 */
	private void get_Asyn(String url, ResultCallback callback) throws IOException{
		Request request = new Request.Builder().url(url).build();
		deliveryResult(callback, request);
	}


	/**
	 * 同步post
	 * @param url
	 * @param params
	 * @return
	 * @throws IOException
	 */
	private Response post_Asyn(String url, HeaderParam[] headerParams, Param[] params) throws IOException{
		Request request = buildPostRequest(url, headerParams, params);
		Response response = mOkHttpClient.newCall(request).execute();
		return response;
	}

	/**
	 * 异步post
	 * @param url
	 * @param callback
	 * @param params
	 * @throws IOException
	 */
	private void post_Asyn(String url, ResultCallback callback, HeaderParam[] headerParams, Param[] params) throws IOException{
		Request request = buildPostRequest(url, headerParams, params);
		deliveryResult(callback, request);
	}


	private void downloadAsyn(final String url, final String destFileDir, final ProgressListener progressListener,final ResultCallback callback) {

		Logger.d("downloadAsyn1="+url);
		final File file = new File(destFileDir);
		final Request request = new Request.Builder().url(url).build();
		final Call call = mOkHttpClient.newCall(request);
		call.enqueue(new Callback() {
			@Override
			public void onFailure(Call call, IOException e) {
				Logger.d("onFailure="+e.toString());
				sendFailedStringCallback(e, callback);
			}

			@Override
			public void onResponse(Call call, Response response) throws IOException {
				InputStream is = null;
				byte[] buf = new byte[2048];
				int len = 0;
				FileOutputStream fos = null;
				try {
					long total = response.body().contentLength();
					Logger.d("total="+total);
					long current = 0;
					is = response.body().byteStream();
					fos = new FileOutputStream(file);
					Logger.d("fos="+total);
					while ((len = is.read(buf)) != -1) {
						current += len;
						fos.write(buf, 0, len);
						Logger.d("current="+current);
						progressListener.update(current, total);

					}
					fos.flush();
					sendSuccessResultCallback(file.getAbsolutePath(), callback);
				} catch (IOException e) {
					Logger.d("IOException="+e.toString());
					sendFailedStringCallback(e, callback);
				} finally {
					try {
						if (is != null) {
							is.close();
						}
						if (fos != null) {
							fos.close();
						}
					} catch (IOException e) {

					}
				}
			}
		});
		/*final Request request = new Request.Builder()
				.url(url)
				.build();
		mOkHttpClient.networkInterceptors().add(new Interceptor() {
			@Override public Response intercept(Interceptor.Chain chain) throws IOException {
				Response originalResponse = chain.proceed(chain.request());
				return originalResponse.newBuilder().body(
						new ProgressResponseBody(originalResponse.body(), progressListener))
						.build();
			}
		});
		Logger.d("progressListener="+progressListener);
		mOkHttpClient.newCall(request).enqueue(new Callback() {

			@Override
			public void onFailure(Call call, IOException e) {
				Logger.d("downloadAsyn"+e.toString());
				sendFailedStringCallback(e, callback);
			}

			@Override
			public void onResponse(Call call, Response response) throws IOException {
				Logger.d("downloadAsyn---onResponse");
				InputStream is = null;
				byte[] buf = new byte[2048];
				int len = 0;
				FileOutputStream fos = null;
				try {
					is = response.body().byteStream();
					File file = new File(destFileDir, getFileName(url));
					Logger.d("destFileDir="+destFileDir);
					fos = new FileOutputStream(file);
					while ((len = is.read(buf)) != -1) {
						fos.write(buf, 0, len);
					}
					fos.flush();
					//如果下载文件成功，第一个参数为文件的绝对路径
					sendSuccessResultCallback(file.getAbsolutePath(), callback);
				} catch (IOException e) {
					sendFailedStringCallback( e, callback);
				} finally {
					try {
						if (is != null) is.close();
					} catch (IOException e) {
					}
					try {
						if (fos != null) fos.close();
					} catch (IOException e) {
					}
				}
			}

		});*/
	}

	private String getFileName(String path)
	{
		int separatorIndex = path.lastIndexOf("/");
		return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1, path.length());
	}

	private Request buildPostRequest(String url, HeaderParam[] headerparams, Param[] params){
		Request.Builder requestBuilder = new Request.Builder();
		if(headerparams == null){
			headerparams = new HeaderParam[0];
		}		
		for (int i = 0; i < headerparams.length; i++) {
			requestBuilder.addHeader(headerparams[i].key, headerparams[i].value);				
		}

		if(params == null){
			params = new Param[0];
		}		
		FormBody.Builder formBodyBuilder = new FormBody.Builder();
		for (int i = 0; i < params.length; i++) {
			formBodyBuilder.add(params[i].key, params[i].value);
		}

		RequestBody requestBody = formBodyBuilder.build();

		Request request = requestBuilder.url(url).post(requestBody).build();
		return request;
	}

	private void deliveryResult(final ResultCallback callback, Request request){

		mOkHttpClient.newCall(request).enqueue(new Callback() {

			@Override
			public void onResponse(Call arg0, Response response){
				try {
					String str = response.body().string();
					if(callback.mType == String.class){
						sendSuccessResultCallback(str, callback);
					}else{
						Object object = mGson.fromJson(str, callback.mType);
						sendSuccessResultCallback(object, callback);
					}
				} catch (IOException e) {
					sendFailedStringCallback(e, callback);
				}

			}

			@Override
			public void onFailure(Call arg0, IOException e) {
				sendFailedStringCallback(e, callback);
			}
		});
	}

	private void sendFailedStringCallback(final Exception e, final ResultCallback callback){
		mDelivery.post(new Runnable(){
			@Override
			public void run(){
				if (callback != null)
					callback.onError(e);
			}
		});
	}


	private void sendSuccessResultCallback(final Object object, final ResultCallback callback){
		mDelivery.post(new Runnable(){
			@Override
			public void run(){
				if (callback != null){
					callback.onResponse(object);
				}
			}
		});
	}

	public static abstract class ResultCallback<T>{
		Type mType;

		public ResultCallback(){
			mType = getSuperclassTypeParameter(getClass());
		}

		static Type getSuperclassTypeParameter(Class<?> subclass){
			Type superclass = subclass.getGenericSuperclass();
			if (superclass instanceof Class){
				throw new RuntimeException("Missing type parameter.");
			}
			ParameterizedType parameterized = (ParameterizedType) superclass;
			return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
		}

		public abstract void onError(Exception e);

		public abstract void onResponse(T response);
	}

	public static class Param{
		String key;
		String value;

		public Param(){
		}

		public Param(String key, String value){
			this.key = key;
			this.value = value;
		}        
	}

	public static class HeaderParam{
		String key;
		String value;
		public HeaderParam(){
		}

		public HeaderParam(String key, String value){
			this.key = key;
			this.value = value;
		}        
	}





	interface ProgressListener {
		/**
		 * @param bytesRead     已下载字节数
		 * @param contentLength 总字节数
		 * @param
		 */
		void update(long bytesRead, long contentLength);
	}
}
